﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text.RegularExpressions;

namespace monitor_client
{
    public delegate IPAddress monitor2to4();
    public partial class IzmersMonitoringForm : Form
    {
        public delegate void listview_invoke(ListViewItem lvi, bool t, byte[] data2send);
        int port = 38803;                                               //Порт для соединени я с измерителями        
        fclose d;
        f4ChangeEventDelegate eventik;
        int NumMax = 0;
        int inum = 0;
        private byte[] reqs = { 0x73, 0x74, 0x72, 0x74 };                          //лучше не рисковать "strt"
        private byte[] reqp = { 0x73, 0x74, 0x6F, 0x70 };                          //стоп прием "stop" 
        private byte[] replyC = { 0x43 };                                          //подтверждение наличия связи
        private byte[] reqc = { 0x63 };                                            //запрос наличия связи от устройства
        private byte[] logs = { 0x6C };                                            //запрос логов
        string[] izmers = new string[99];
        delegate void TextData(byte[] data, int num, string name);
        
        
        //public Form4(monitor2to4 sender, fclose sender1)
        public IzmersMonitoringForm(f4ChangeEventDelegate sender1, fclose sender2)
        {
            InitializeComponent();
            //get_ip = sender;
            eventik = sender1;
            d = sender2;
            eventik(AddIzmerMonitor, true);
            try
            {
                izmers = File.ReadAllLines(@"resources\adresses_temp.ini");
            }
            catch (FileNotFoundException)
            {
                MessageBox.Show("Файл adresses_temp.ini не найден.");
                this.Close();
            }
            listView1.View = View.Details;
            listView1.FullRowSelect = true;
            listView1.Columns.Add("Название устройства");
            listView1.Columns[listView1.Columns.Count - 1].Width = 130;
            listView1.Columns.Add("Зона выделения");
            listView1.Columns[listView1.Columns.Count - 1].Width = 100;
            listView1.Columns.Add("Дата/Время");
            listView1.Columns[listView1.Columns.Count - 1].Width = 80;
            listView1.Columns.Add("Качество сигнала");
            listView1.Columns[listView1.Columns.Count - 1].Width = 110;
            listView1.Columns.Add("Эталон, с");
            listView1.Columns[listView1.Columns.Count - 1].Width = 75;
            listView1.Columns.Add("Норма, мкс");
            listView1.Columns[listView1.Columns.Count - 1].Width = 75;
            listView1.Columns.Add("Задержка, с");
            listView1.Columns[listView1.Columns.Count - 1].Width = 75;
            listView1.Columns.Add("Разница, с");
            listView1.Columns[listView1.Columns.Count - 1].Width = 75;
            listView1.Columns.Add("Количество спутников");
            listView1.Columns[listView1.Columns.Count - 1].Width = 130;
        }

        public class ConnectionIzm
        {
            public Socket Socket;
            public byte[] Buffer = new byte[41];
            public int wait_c;
            public bool status;
            public IPEndPoint ipe;
            public IPEndPoint lpe;
            public string name;
            public string blr;
            public int num;
            public ListViewItem item;
            public Timer tim;
        }

        private List<ConnectionIzm> _connections = new List<ConnectionIzm>();

        private void lv_inv(ListViewItem lvi, bool t, byte[] data2send)
        {
            string norm = Encoding.ASCII.GetString(data2send).Substring(24, 1) + ',' + Encoding.ASCII.GetString(data2send).Substring(25, 1);
            string lvi_norm = ((ListViewItem)lvi).SubItems[5].Text;
            string pattern = @"\d\,\d";
            if (!Regex.IsMatch(norm, pattern) || !Regex.IsMatch(lvi_norm, pattern))
                return;
            if (!t)
                listView1.Items.Add(lvi);
            else
            {
                //((ListViewItem)lvi).SubItems[2].Text = Encoding.ASCII.GetString(data2send).Substring(0, 11);      //время
                ((ListViewItem)lvi).SubItems[2].Text = Encoding.ASCII.GetString(data2send).Substring(6, 5) + "/" + Encoding.ASCII.GetString(data2send).Substring(0, 5);      //время
                ((ListViewItem)lvi).SubItems[3].Text = Encoding.ASCII.GetString(data2send).Substring(11, 1);      //качество сигнала
                ((ListViewItem)lvi).SubItems[4].Text = "0," + Encoding.ASCII.GetString(data2send).Substring(17, 7);      //эталон
                ((ListViewItem)lvi).SubItems[5].Text = Encoding.ASCII.GetString(data2send).Substring(24, 1) + ',' + Encoding.ASCII.GetString(data2send).Substring(25, 1);      //норма
                ((ListViewItem)lvi).SubItems[6].Text = "0," + Encoding.ASCII.GetString(data2send).Substring(26, 7);      //задержка
                ((ListViewItem)lvi).SubItems[7].Text = "0," + Encoding.ASCII.GetString(data2send).Substring(33, 7);      //разница
                ((ListViewItem)lvi).SubItems[8].Text = Encoding.ASCII.GetString(data2send).Substring(12, 5);      //количество спутников                
            
            }
        }

        private void AsyncRecvCallback(IAsyncResult ar)
        {
            ConnectionIzm state = (ConnectionIzm)ar.AsyncState;
            state.tim.Stop();
            
            Socket soc = state.Socket;
            try
            {
                soc.EndReceive(ar);
            }
            catch (ObjectDisposedException)
            {
                return;
            }
            catch (SocketException)
            {
                CloseConnection(state);
                MessageBox.Show("Имя: " + state.name + ".\n"
                                + "IP-адрес: " + state.ipe.Address + ".\n\n"
                                + "Получен неверный ответ от устройства. "
                                + "Возможно под данным IP-адресом в сети зарегистрировано другое устройство.");
                return;
            }
            catch (Exception)
            {
                return;
            }

            state.wait_c = 3;
            state.status = true;
            try
            {
                if (state.Buffer[0] == reqc[0])
                    soc.EndSendTo(soc.BeginSendTo(replyC, 0, 1, 0, state.ipe, null, null));
                else
                {
                    TextData d = textwrite;
                    textwrite(state.Buffer, state.num, state.name);
                }
            }
            catch (SocketException)
            {

                return;
            }
            catch (Exception)
            { }
            state.tim.Start();
            try
            {
                soc.EndSendTo(soc.BeginSendTo(reqs, 0, reqs.Length, 0, state.ipe, null, null));
                soc.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(AsyncRecvCallback), state);
            }
            catch (Exception)
            {
                
                return;
            }
        }

        void textwrite(byte[] data2send, int num, string name)
        {
            listview_invoke lvin = lv_inv;
            if (_connections[num].item != null)
            {
                listView1.Invoke(lvin, _connections[num].item, true, data2send);
                /*((ListViewItem)_connections[num].item).SubItems[2].Text = Encoding.ASCII.GetString(data2send).Substring(0, 11);      //время
                ((ListViewItem)_connections[num].item).SubItems[3].Text = Encoding.ASCII.GetString(data2send).Substring(11, 1);      //качество сигнала
                ((ListViewItem)_connections[num].item).SubItems[4].Text = "0," + Encoding.ASCII.GetString(data2send).Substring(17, 7);      //эталон
                ((ListViewItem)_connections[num].item).SubItems[5].Text = Encoding.ASCII.GetString(data2send).Substring(24, 1) + ',' + Encoding.ASCII.GetString(data2send).Substring(25, 1);      //норма
                ((ListViewItem)_connections[num].item).SubItems[6].Text = "0," + Encoding.ASCII.GetString(data2send).Substring(26, 7);      //задержка
                ((ListViewItem)_connections[num].item).SubItems[7].Text = "0," + Encoding.ASCII.GetString(data2send).Substring(33, 7);      //разница
                ((ListViewItem)_connections[num].item).SubItems[8].Text = Encoding.ASCII.GetString(data2send).Substring(12, 5);      //количество спутников                
                 */
            }
            else
            {
                _connections[num].item = new ListViewItem(_connections[num].name);
                _connections[num].item.SubItems.Add(_connections[num].blr);
                //_connections[num].item.SubItems.Add(Encoding.ASCII.GetString(data2send).Substring(0, 11));      //время
                _connections[num].item.SubItems.Add(Encoding.ASCII.GetString(data2send).Substring(6, 5) + "/" + Encoding.ASCII.GetString(data2send).Substring(0, 5));//время
                _connections[num].item.SubItems.Add(Encoding.ASCII.GetString(data2send).Substring(11, 1));      //качество сигнала
                _connections[num].item.SubItems.Add(Encoding.ASCII.GetString(data2send).Substring(17, 7));      //эталон
                _connections[num].item.SubItems.Add(Encoding.ASCII.GetString(data2send).Substring(24, 1) + ',' + Encoding.ASCII.GetString(data2send).Substring(25, 1)); //норма
                _connections[num].item.SubItems.Add(Encoding.ASCII.GetString(data2send).Substring(26, 7));      //задержка
                _connections[num].item.SubItems.Add(Encoding.ASCII.GetString(data2send).Substring(33, 7));      //разница
                _connections[num].item.SubItems.Add(Encoding.ASCII.GetString(data2send).Substring(12, 5));      //количество спутников
                try
                {
                    listView1.Invoke(lvin,_connections[num].item, false, data2send);
                }
                catch (Exception)
                { }
            }
        }

        private void f_close()
        {
            foreach (ConnectionIzm connect in _connections)
            {
                try
                {
                    connect.Socket.EndSendTo(connect.Socket.BeginSendTo(reqp, 0, reqp.Length, 0, connect.ipe, null, null));
                    connect.Socket.Shutdown(SocketShutdown.Both);
                    connect.Socket.Close();
                }
                catch (Exception)
                { }
                inum--;
                connect.status = false;
            }
            
        }

        private static bool trueone()
        {
            return true;
        }

        private void CloseConnection(ConnectionIzm ci)                     //CloseConnection
        {
            int num = ci.num;
            
            try
            {
                ci.Socket.EndSendTo(ci.Socket.BeginSendTo(reqp, 0, reqp.Length, 0, ci.ipe, null, null));
                ci.Socket.Shutdown(SocketShutdown.Both);
                ci.Socket.Close();
            }
            catch
            {

            }            
            try
            {
                int position = -1;
                foreach (ListViewItem item in listView1.Items)
                    if (item.Text == ci.name)
                    {
                        position = item.Index;
                        break;
                    }
                if (position != -1)
                    listView1.Items[position].Remove();
            }
            catch (Exception)
            { }
            //-----------------------------------------------------------------------------------------
            lock (_connections) _connections.Remove(ci);
            inum--;
            foreach (ConnectionIzm connect in _connections)
            {                
                    if (connect.num > num)
                        connect.num--;
            }
            ci.status = false;

        }

        //Новое устройство в список мониторящихся
        private void AddIzmerMonitor(IPAddress new_ip)
        {
            int num_port = 0;
            //izmers = File.ReadAllLines(@"resources\adresses_temp.ini");
            int i = 0; int j = 0; int k = 0;
            if (this.Enabled == true)
            {
                foreach (ConnectionIzm connection in _connections)
                {
                    if (connection.ipe.Address.ToString() == new_ip.ToString())
                        return;
                }
                ConnectionIzm connect = new ConnectionIzm();
                lock (_connections) _connections.Add(connect);
                connect.ipe = new IPEndPoint(new_ip, 38803);               
                connect.status = true;
                connect.wait_c = 3;
                connect.num = inum;
                i = 0; j = 0; k = 0;
                while (i < izmers.Length)
                {
                    j = 0;
                    while (izmers[i][j] != '=')
                        j++;
                    if (new_ip.ToString() == izmers[i].Substring(0, j))
                        break;
                    i++;
                }
                j++;
                while (izmers[i][k] != ',')
                {
                    k++;
                }
                connect.name = izmers[i].Substring(j, k - j);
                k++;
                connect.blr = izmers[i].Substring(k);
                connect.Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                while (true)
                    try
                    {
                        connect.lpe = new IPEndPoint(IPAddress.Any, port + num_port);
                        connect.Socket.Bind(connect.lpe);
                        break;
                    }
                    catch (SocketException)
                    {
                        num_port++;
                    }
                if (num_port > NumMax)
                    NumMax = num_port;
                try
                {
                    connect.Socket.EndSendTo(connect.Socket.BeginSendTo(reqs, 0, reqs.Length, 0, connect.ipe, null, null));
                }
                catch (SocketException)
                {
                    CloseConnection(connect);
                    //MessageBox.Show("нет связи с устройством " + connect.name);
                    return;
                }
                catch (Exception)
                { }

                try
                {
                    connect.Socket.BeginReceive(connect.Buffer, 0, connect.Buffer.Length, SocketFlags.None, new AsyncCallback(AsyncRecvCallback), connect);
                }
                catch (SocketException)
                {
                    CloseConnection(connect);
                    //return;
                    MessageBox.Show("Имя: " + connect.name + ".\n"
                                + "IP-адрес: " + connect.ipe.Address + ".\n\n"
                                + "Получен неверный ответ от устройства. "
                                + "Возможно под данным IP-адресом в сети зарегистрировано другое устройство.");
                }
                inum++;
                connect.tim = new Timer();
                EventArgs a = new EventArgs();
                connect.tim.Tick += new EventHandler(tim_Tick);
                connect.tim.Interval = 3000;
                connect.tim.Tag = connect.name;
                connect.tim.Start();

            }
        }

        void tim_Tick(object sender, EventArgs e)
        {
            Timer t = sender as Timer;
            t.Stop();
            //--------------Смотреть сюда-------------------------------------------могут быть проблемы с индексами
            string n = (string)t.Tag; 
            int i = 0;
            foreach (ConnectionIzm connection in _connections)
            {
                if (connection.name == n)
                    break;
                i++;
            }
            if (_connections.Count > i)
            {
                CloseConnection(_connections[i]);
                MessageBox.Show("Потеряна связь с устройством " + n);
            }
            //Timer t = sender as Timer;
            //t.Stop();
            ////--------------Смотреть сюда-------------------------------------------могут быть проблемы с индексами
            //string n = (string)t.Tag;
            //int i = 0;
            //foreach (ConnectionIzm connection in _connections)
            //{
            //    if (connection.name == n)
            //        break;
            //    i++;
            //}
            //CloseConnection(_connections[i]);
            //MessageBox.Show("Потеряна связь с устройством " + n);
        }
        
        private void Form4_FormClosing(object sender, FormClosingEventArgs e)    //закрытие формы
        {
            f_close();
            eventik(AddIzmerMonitor, false);
            d(false);
        }

        private void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left)
                return;
            int i = listView1.FocusedItem.Index;
            try
            {
                CloseConnection(_connections[i]);
            }
            catch (Exception)
            { }
        }

        
    }
}
